#include "User_dev_spi.h"
#include "driver/spi_master.h"
#include "esp_log.h"
#include <string.h>
#include "driver/gpio.h"

#define LCD_DC_SET() gpio_set_level(LCD_DC, 1);
#define LCD_DC_CLR() gpio_set_level(LCD_DC, 0);

#define SPI_TRANSACTION_NUM (80) // 定义具体需要多少个消息队列

static spi_device_handle_t spi; // 创建spi
/*SPI队列资源池*/
static spi_transaction_t user_spi_transaction[SPI_TRANSACTION_NUM];
static uint8_t user_spi_transaction_cnt = 0;
extern void spi_disp_flush_ready(void);

IRAM_ATTR static void spi_ready(spi_transaction_t *trans)
{
    uint32_t spi_cnt = (uint32_t)trans->user;

    if (spi_cnt == SPI_WRITE_DATA_OVER)
    {
        spi_disp_flush_ready();
    }
}

IRAM_ATTR static void spi_pre_cb(spi_transaction_t *trans)
{
    uint32_t flag = (uint32_t)trans->user;
    switch (flag)
    {
    case SPI_WRITE_NONE: // 不需要要处理的情况

        break;
    case SPI_WRITE_REG:
        LCD_DC_CLR();
        break;
    case SPI_WRITE_DATA:
        LCD_DC_SET();
        break;
    case SPI_WRITE_DATA_OVER:
        LCD_DC_SET();
        break;

    default:
        break;
    }
}

/*spi总线定义*/
static const spi_bus_config_t buscfg = {
    .miso_io_num = PIN_NUM_MISO,
    .mosi_io_num = PIN_NUM_MOSI,
    .sclk_io_num = PIN_NUM_CLK,
    .quadwp_io_num = -1,
    .quadhd_io_num = -1,
    .max_transfer_sz = 4094,
};

static const spi_device_interface_config_t devcfg = {
    .clock_speed_hz = SPI_MASTER_FREQ_80M, // ST7789 最高只能一般只能到62.5Mhz，所以这边量产不建议用80Mhz
    .mode = 0,
    .spics_io_num = PIN_NUM_CS,
    .queue_size = SPI_TRANSACTION_NUM,
    .cs_ena_pretrans = 1,
    .post_cb = spi_ready, // 注册一个SPI调用完成的回调
    .pre_cb = spi_pre_cb,
};

void vspi_init(void)
{
    gpio_reset_pin(LCD_DC);
    gpio_set_direction(LCD_DC, GPIO_MODE_OUTPUT); // 设置DC为输出模式
    spi_bus_initialize(SPI3_HOST, &buscfg, SPI_DMA_CH_AUTO);
    spi_bus_add_device(SPI3_HOST, &devcfg, &spi);
}

IRAM_ATTR void VSPI_data_queue(uint16_t *dat, uint32_t len, SPI_WRITE_MODE_t user_fg)
{
    memset(&user_spi_transaction[user_spi_transaction_cnt], 0, sizeof(spi_transaction_t)); // Zero out the transaction
    user_spi_transaction[user_spi_transaction_cnt].length = len;                           // Command is 8 bits
    user_spi_transaction[user_spi_transaction_cnt].tx_buffer = dat;                        // The data is the cmd itself
    user_spi_transaction[user_spi_transaction_cnt].user = (void *)user_fg;                 // D/C needs to be set to 0
    esp_err_t ret = spi_device_queue_trans(spi, &user_spi_transaction[user_spi_transaction_cnt], portMAX_DELAY);
    assert(ret == ESP_OK); // Should have had no issues.
    user_spi_transaction_cnt++;
    if (user_spi_transaction_cnt == SPI_TRANSACTION_NUM)
    {
        user_spi_transaction_cnt = 0;
    }
}

IRAM_ATTR void VSPI_data_queue_8bit(uint8_t val, SPI_WRITE_MODE_t dc_state)
{
    memset(&user_spi_transaction[user_spi_transaction_cnt], 0, sizeof(spi_transaction_t)); // Zero out the transaction
    user_spi_transaction[user_spi_transaction_cnt].length = 8;                             // Command is 8 bits
    user_spi_transaction[user_spi_transaction_cnt].flags = SPI_TRANS_USE_TXDATA;           // Command is 8 bits
    user_spi_transaction[user_spi_transaction_cnt].tx_data[0] = val;                       // Command is 8 bits
    user_spi_transaction[user_spi_transaction_cnt].user = (void *)dc_state;                // Command is 8 bits
    esp_err_t ret = spi_device_queue_trans(spi, &user_spi_transaction[user_spi_transaction_cnt], portMAX_DELAY);
    assert(ret == ESP_OK); // Should have had no issues.
    user_spi_transaction_cnt++;
    if (user_spi_transaction_cnt == SPI_TRANSACTION_NUM)
    {
        user_spi_transaction_cnt = 0;
    }
}

IRAM_ATTR void VSPI_data_queue_REG_8bit(uint8_t reg)
{
    VSPI_data_queue_8bit(reg, SPI_WRITE_REG);
}

IRAM_ATTR void VSPI_data_queue_data_8bit(uint8_t data)
{
    VSPI_data_queue_8bit(data, SPI_WRITE_DATA);
}

IRAM_ATTR void VSPI_data_queue_data_32bit(uint8_t data1, uint8_t data2, uint8_t data3, uint8_t data4)
{
    memset(&user_spi_transaction[user_spi_transaction_cnt], 0, sizeof(spi_transaction_t)); // Zero out the transaction
    user_spi_transaction[user_spi_transaction_cnt].length = 32;
    user_spi_transaction[user_spi_transaction_cnt].flags = SPI_TRANS_USE_TXDATA;  // Command is 8 bits
    user_spi_transaction[user_spi_transaction_cnt].tx_data[0] = data1;            // Command is 8 bits
    user_spi_transaction[user_spi_transaction_cnt].tx_data[1] = data2;            // Command is 8 bits
    user_spi_transaction[user_spi_transaction_cnt].tx_data[2] = data3;            // Command is 8 bits
    user_spi_transaction[user_spi_transaction_cnt].tx_data[3] = data4;            // Command is 8 bits
    user_spi_transaction[user_spi_transaction_cnt].user = (void *)SPI_WRITE_DATA; // Command is 8 bits
    esp_err_t ret = spi_device_queue_trans(spi, &user_spi_transaction[user_spi_transaction_cnt], portMAX_DELAY);
    assert(ret == ESP_OK); // Should have had no issues.
    user_spi_transaction_cnt++;
    if (user_spi_transaction_cnt == SPI_TRANSACTION_NUM)
    {
        user_spi_transaction_cnt = 0;
    }
}
